home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / MBUF.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  9KB  |  440 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "proc.h"
  7.  
  8. /* Allocate mbuf with associated buffer of 'size' bytes */
  9. struct mbuf *
  10. alloc_mbuf(size)
  11. register int16 size;
  12. {
  13.     register struct mbuf *bp;
  14.  
  15.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  16.         return NULLBUF;
  17.  
  18.     bp->next = bp->anext = NULLBUF;
  19.     if(size != 0){
  20.         bp->data = (char *)(bp + 1);
  21.     } else {
  22.         bp->data = NULLCHAR;
  23.     }
  24.     bp->refcnt = 1;
  25.     bp->dup = NULLBUF;
  26.     bp->size = size;
  27.     bp->cnt = 0;
  28.     return bp;
  29. }
  30.  
  31. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  32.  * free all resources associated with mbuf.
  33.  * Return pointer to next mbuf in packet chain
  34.  */
  35. struct mbuf *
  36. free_mbuf(bp)
  37. register struct mbuf *bp;
  38. {
  39.     register struct mbuf *bp1 = NULLBUF;
  40.  
  41.     if(bp != NULLBUF){
  42.         bp1 = bp->next;
  43.         /* Follow indirection, if any */
  44.         free_mbuf(bp->dup);
  45.  
  46.         if(--bp->refcnt == 0)
  47.             free((char *)bp);
  48.     }
  49.     return bp1;
  50. }
  51.  
  52. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  53.  * if any
  54.  */
  55. struct mbuf *
  56. free_p(bp)
  57. register struct mbuf *bp;
  58. {
  59.     register struct mbuf *abp;
  60.  
  61.     if(bp == NULLBUF)
  62.         return NULLBUF;
  63.     abp = bp->anext;
  64.     while(bp != NULLBUF)
  65.         bp = free_mbuf(bp);
  66.     return abp;
  67. }        
  68. /* Free entire queue of packets (of mbufs) */
  69. void
  70. free_q(q)
  71. struct mbuf **q;
  72. {
  73.     register struct mbuf *bp;
  74.  
  75.     while((bp = dequeue(q)) != NULLBUF)
  76.         free_p(bp);
  77. }
  78.  
  79. /* Count up the total number of bytes in an mbuf */
  80. int16
  81. len_mbuf(bp)
  82. register struct mbuf *bp;
  83. {
  84.     register int16 cnt = 0;
  85.  
  86.     while(bp != NULLBUF){
  87.         cnt += bp->cnt;
  88.         bp = bp->next;
  89.     }
  90.     return cnt;
  91. }
  92. /* Count up the number of packets in a queue */
  93. int16
  94. len_q(bp)
  95. register struct mbuf *bp;
  96. {
  97.     register int16 cnt;
  98.  
  99.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  100.         ;
  101.     return cnt;
  102. }
  103. /* Trim mbuf to specified length by lopping off end */
  104. void
  105. trim_mbuf(bpp,length)
  106. struct mbuf **bpp;
  107. int16 length;
  108. {
  109.     register int16 tot = 0;
  110.     register struct mbuf *bp;
  111.  
  112.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  113.         return;    /* Nothing to trim */
  114.  
  115.     if(length == 0){
  116.         /* Toss the whole thing */
  117.         free_p(*bpp);
  118.         *bpp = NULLBUF;
  119.         return;
  120.     }
  121.     /* Find the point at which to trim. If length is greater than
  122.      * the packet, we'll just fall through without doing anything
  123.      */
  124.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  125.         if(tot + bp->cnt < length){
  126.             tot += bp->cnt;
  127.         } else {
  128.             /* Cut here */
  129.             bp->cnt = length - tot;
  130.             free_p(bp->next);
  131.             bp->next = NULLBUF;
  132.             break;
  133.         }
  134.     }
  135. }
  136. /* Duplicate/enqueue/dequeue operations based on mbufs */
  137.  
  138. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  139.  * This is done without copying data; only the headers are duplicated,
  140.  * but without data segments of their own. The pointers are set up to
  141.  * share the data segments of the original copy. The return pointer is
  142.  * passed back through the first argument, and the return value is the
  143.  * number of bytes actually duplicated.
  144.  */
  145. int16
  146. dup_p(hp,bp,offset,cnt)
  147. struct mbuf **hp;
  148. register struct mbuf *bp;
  149. register int16 offset;
  150. register int16 cnt;
  151. {
  152.     register struct mbuf *cp;
  153.     int16 tot;
  154.  
  155.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  156.         if(hp != NULLBUFP)
  157.             *hp = NULLBUF;
  158.         return 0;
  159.     }
  160.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  161.         return 0;
  162.     }
  163.     /* Skip over leading mbufs that are smaller than the offset */
  164.     while(bp != NULLBUF && bp->cnt <= offset){
  165.         offset -= bp->cnt;
  166.         bp = bp->next;
  167.     }
  168.     if(bp == NULLBUF){
  169.         free_mbuf(cp);
  170.         *hp = NULLBUF;
  171.         return 0;    /* Offset was too big */
  172.     }
  173.     tot = 0;
  174.     for(;;){
  175.         /* Make sure we get the original, "real" buffer (i.e. handle the
  176.          * case of duping a dupe)
  177.          */
  178.         if(bp->dup != NULLBUF)
  179.             cp->dup = bp->dup;
  180.         else
  181.             cp->dup = bp;
  182.  
  183.         /* Increment the duplicated buffer's reference count */
  184.         cp->dup->refcnt++;
  185.  
  186.         cp->data = bp->data + offset;
  187.         cp->cnt = min(cnt,bp->cnt - offset);
  188.         offset = 0;
  189.         cnt -= cp->cnt;
  190.         tot += cp->cnt;
  191.         bp = bp->next;
  192.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  193.             break;
  194.         cp = cp->next;
  195.     }
  196.     return tot;
  197. }
  198. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  199. struct mbuf *
  200. copy_p(bp,cnt)
  201. register struct mbuf *bp;
  202. register int16 cnt;
  203. {
  204.     register struct mbuf *cp;
  205.     register char *wp;
  206.     register int16 n;
  207.  
  208.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  209.         return NULLBUF;
  210.     wp = cp->data;
  211.     while(cnt != 0 && bp != NULLBUF){
  212.         n = min(cnt,bp->cnt);
  213.         memcpy(wp,bp->data,n);
  214.         wp += n;
  215.         cp->cnt += n;
  216.         cnt -= n;
  217.         bp = bp->next;
  218.     }
  219.     return cp;
  220. }
  221. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  222.  * bytes actually pulled off
  223.  */
  224. int16
  225. pullup(bph,buf,cnt)
  226. struct mbuf **bph;
  227. char *buf;
  228. int16 cnt;
  229. {
  230.     register struct mbuf *bp;
  231.     int16 n,tot;
  232.  
  233.     tot = 0;
  234.     if(bph == NULLBUFP)
  235.         return 0;
  236.     while(*bph != NULLBUF && cnt != 0){
  237.         bp = *bph;
  238.         n = min(cnt,bp->cnt);
  239.         if(buf != NULLCHAR){
  240.             if(n == 1)    /* Common case optimization */
  241.                 *buf = *bp->data;
  242.             else if(n > 1)
  243.                 memcpy(buf,bp->data,n);
  244.             buf += n;
  245.         }
  246.         tot += n;
  247.         cnt -= n;
  248.         bp->data += n;
  249.         bp->cnt -= n;        
  250.         if(bp->cnt == 0){
  251.             *bph = free_mbuf(bp);
  252.         }
  253.     }
  254.     return tot;
  255. }
  256. /* Append mbuf to end of mbuf chain */
  257. void
  258. append(bph,bp)
  259. struct mbuf **bph;
  260. struct mbuf *bp;
  261. {
  262.     register struct mbuf *p;
  263.  
  264.     if(bph == NULLBUFP || bp == NULLBUF)
  265.         return;
  266.     if(*bph == NULLBUF){
  267.         /* First one on chain */
  268.         *bph = bp;
  269.     } else {
  270.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  271.             ;
  272.         p->next = bp;
  273.     }
  274. }
  275. /* Insert specified amount of contiguous new space at the beginning of an
  276.  * mbuf chain. If enough space is available in the first mbuf, no new space
  277.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  278.  * tacked on the front of the chain.
  279.  *
  280.  * This operation is the logical inverse of pullup(), hence the name.
  281.  */
  282. struct mbuf *
  283. pushdown(bp,size)
  284. register struct mbuf *bp;
  285. int16 size;
  286. {
  287.     register struct mbuf *nbp;
  288.  
  289.     /* Check that bp is real, that it hasn't been duplicated, and
  290.      * that it itself isn't a duplicate before checking to see if
  291.      * there's enough space at its front.
  292.      */
  293.     if(bp != NULLBUF && bp->refcnt == 1 && bp->size != 0
  294.      && bp->data - (char *)(bp+1) >= size){
  295.         /* No need to alloc new mbuf, just adjust this one */
  296.         bp->data -= size;
  297.         bp->cnt += size;
  298.     } else {
  299.         if((nbp = alloc_mbuf(size)) != NULLBUF){
  300.             nbp->next = bp;
  301.             nbp->cnt = size;
  302.             bp = nbp;
  303.         } else {
  304.             bp = NULLBUF;
  305.         }
  306.     }
  307.     return bp;
  308. }
  309. /* Append packet to end of packet queue */
  310. void
  311. enqueue(q,bp)
  312. struct mbuf **q;
  313. struct mbuf *bp;
  314. {
  315.     register struct mbuf *p;
  316.     char i_state;
  317.  
  318.     if(q == NULLBUFP || bp == NULLBUF)
  319.         return;
  320.     i_state = dirps();
  321.     if(*q == NULLBUF){
  322.         /* List is empty, stick at front */
  323.         *q = bp;
  324.     } else {
  325.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  326.             ;
  327.         p->anext = bp;
  328.     }
  329.     restore(i_state);
  330.     psignal(q,1);
  331. }
  332. /* Unlink a packet from the head of the queue */
  333. struct mbuf *
  334. dequeue(q)
  335. register struct mbuf **q;
  336. {
  337.     register struct mbuf *bp;
  338.     char i_state;
  339.  
  340.     if(q == NULLBUFP)
  341.         return NULLBUF;
  342.     i_state = dirps();
  343.     if((bp = *q) != NULLBUF){
  344.         *q = bp->anext;
  345.         bp->anext = NULLBUF;
  346.     }
  347.     restore(i_state);
  348.     return bp;
  349. }    
  350.  
  351. /* Copy user data into an mbuf */
  352. struct mbuf *
  353. qdata(data,cnt)
  354. char *data;
  355. int16 cnt;
  356. {
  357.     register struct mbuf *bp;
  358.  
  359.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  360.         return NULLBUF;
  361.     memcpy(bp->data,data,cnt);
  362.     bp->cnt = cnt;
  363.     return bp;
  364. }
  365. /* Copy mbuf data into user buffer */
  366. int16
  367. dqdata(bp,buf,cnt)
  368. struct mbuf *bp;
  369. char *buf;
  370. unsigned cnt;
  371. {
  372.     int16 tot;
  373.     unsigned n;
  374.     struct mbuf *bp1;
  375.  
  376.     if(buf == NULLCHAR)
  377.         return 0;
  378.     
  379.     tot = 0;
  380.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  381.         n = min(bp1->cnt,cnt);
  382.         memcpy(buf,bp1->data,n);
  383.         cnt -= n;
  384.         buf += n;
  385.         tot += n;
  386.     }
  387.     free_p(bp);
  388.     return tot;
  389. }
  390. /* Pull a 32-bit integer in host order from buffer in network byte order */
  391. int32
  392. pull32(bpp)
  393. struct mbuf **bpp;
  394. {
  395.     char buf[4];
  396.  
  397.     if(pullup(bpp,buf,4) != 4){
  398.         /* Return zero if insufficient buffer */
  399.         return 0;
  400.     }
  401.     return get32(buf);
  402. }
  403. /* Pull a 16-bit integer in host order from buffer in network byte order */
  404. int16
  405. pull16(bpp)
  406. struct mbuf **bpp;
  407. {
  408.     char buf[2];
  409.  
  410.     if(pullup(bpp,buf,2) != 2){
  411.         /* Return zero if insufficient buffer */
  412.         return 0;
  413.     }
  414.     return get16(buf);
  415. }
  416. /* Pull single character from mbuf */
  417. char
  418. pullchar(bpp)
  419. struct mbuf **bpp;
  420. {
  421.     char c;
  422.  
  423.     if(pullup(bpp,&c,1) != 1)
  424.         /* Return zero if nothing left */
  425.         c = 0;
  426.     return c;
  427. }
  428. int
  429. write_p(fp,bp)
  430. FILE *fp;
  431. struct mbuf *bp;
  432. {
  433.     while(bp != NULLBUF){
  434.         if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  435.             return -1;
  436.         bp = bp->next;
  437.     }
  438.     return 0;
  439. }
  440.